package com.zyso.config;

import cn.hutool.core.collection.ListUtil;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.zyso.pojo.Site;
import com.zyso.service.ZySoService;
import com.zyso.vo.SearchResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class SearchResultCacheConfig {

    @Autowired
    private ZySoService zySoService;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private SitesConfig sitesConfig;

    /**
     * 一次最大call数量
     */
    public static final int MAX_CALL_COUNT = 5;
    /**
     * 超时范围
     */
    private static final Long[] TIME_OUT_RANGE = {8L, 15L};

    private final Cache<String, List<SearchResultVO>> searchResultCache = Caffeine.newBuilder()
            //  数量上限
            .maximumSize(50)
            //  从最后一次写入后多久就会过期
            .expireAfterWrite(300, TimeUnit.SECONDS).build();

    public List<SearchResultVO> getSearchResultCache(String key) {
        return searchResultCache.get(key, e -> {
            //  stopwatch
            Stopwatch stopwatch = Stopwatch.createStarted();
            //  源集合
            List<Site> siteList = sitesConfig.getSites();
            List<SearchResultVO> list = Lists.newArrayList();
            //  分页
            int pageNo = 0;
            boolean hasRemaining;
            do {
                List<Site> limitList = ListUtil.page(pageNo, MAX_CALL_COUNT, siteList);
                hasRemaining = limitList.size() == MAX_CALL_COUNT;
                if (CollectionUtils.isEmpty(limitList)) {
                    continue;
                }
                pageNo++;
                Future<List<SearchResultVO>> future = threadPoolExecutor.submit(() -> zySoService.search(limitList, e));
                try {
                    List<SearchResultVO> resultList = future.get(TIME_OUT_RANGE[1], TimeUnit.SECONDS);
                    list.addAll(resultList);
                    //  搜索结果评分
                    sitesConfig.resultScore(limitList, resultList);
                } catch (Exception exception) {
                    log.error("", exception);
                    future.cancel(true);
                }
                long elapsed = stopwatch.elapsed(TimeUnit.SECONDS);
                //  最大时间
                if (elapsed >= TIME_OUT_RANGE[1]) {
                    stopwatch.stop();
                    log.info("{} MAX COST {} {}", e, elapsed, pageNo);
                    return list;
                }
                //  判断结果
                if (CollectionUtils.isEmpty(list)) {
                    //  大于最小时间，否则继续搜索
                    if (elapsed > TIME_OUT_RANGE[0]) {
                        stopwatch.stop();
                        log.info("{} NO RESULT COST {} {}", e, elapsed, pageNo);
                        return list;
                    }
                } else {
                    stopwatch.stop();
                    log.info("{} COST {}", e, elapsed);
                    return list;
                }
            } while (hasRemaining);
            stopwatch.stop();
            return list;
        });
    }

    public int getSearchResultCacheSize() {
        return searchResultCache.asMap().size();
    }

}
